﻿using HalconDotNet;
using MetroFramework.Forms;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using 多尺度相机采集.Properties;

namespace 多尺度相机采集
{
    public partial class Form2 : MetroForm
    {
        Camera[] m_MyCamera;
        string[] m_CameraList;
        HObject[] m_Image;
        HObject m_TestImage = null;
        HTuple[] hv_WindowHandle;
        bool[] isOpened, isGrabing;
        bool[] deviceOpen;  //判断相机对否打开成功
        int m_CHNum = 2;
        DateTime[] dateTimes;
        string baseImagePath;
        MyHalcon m_MyHalcon = new MyHalcon();
        HWindowControl[] hWindowControl = new HWindowControl[2];
        Label[] lab_LED                 = new Label[2];
        Label[] lab_FPS                 = new Label[2];
        Label[] lab_Gain                = new Label[2];
        Label[] lab_Expo                = new Label[2];
        TextBox[] textBoxes_Expo        = new TextBox[2];
        TextBox[] textBoxes_Gain        = new TextBox[2];
        bool flag = false;   //定时器2 的触发标致
        public Form2()
        {
            InitializeComponent();
            deviceOpen = new bool[m_CHNum];
            isOpened        = new bool[m_CHNum];
            isGrabing       = new bool[m_CHNum];
            m_MyCamera        = new Camera[m_CHNum];
            m_Image         = new HObject[m_CHNum];
            hv_WindowHandle = new HTuple[m_CHNum];
            dateTimes       = new DateTime[m_CHNum];
            for (int i = 0; i < m_CHNum; i++)
            {
                deviceOpen[i] = false;    //默认为没打开成功
                isOpened[i]   = false;
                isGrabing[i]  = false;
            }
            hWindowControl[0] = hWindowControl1;
            hWindowControl[1] = hWindowControl2;
            lab_LED[0]        = ld1;
            lab_LED[1]        = ld2;
            lab_FPS[0]        = lab_FPS1;
            lab_FPS[1]        = lab_FPS2;
            lab_Gain[0]       = lab_Gain1;
            lab_Gain[1]       = lab_Gain2;
            lab_Expo[0]       = lab_Expo1;
            lab_Expo[1]       = lab_Expo2;
            textBoxes_Expo[0] = textBox_Expo1;
            textBoxes_Expo[1] = textBox_Expo2;
            textBoxes_Gain[0] = textBox_Gain1;
            textBoxes_Gain[1] = textBox_Gain2;
            // 获取相机列表
            HOperatorSet.InfoFramegrabber("USB3Vision", "devices", out HTuple information, out HTuple list);
            string[] deviceList = list.ToSArr();
            m_CameraList = new string[deviceList.Length];
            for (int i = 0; i < deviceList.Length; ++i)
            {
                int begin = deviceList[i].IndexOf("unique_name:");
                int end = deviceList[i].IndexOf(" |", begin);
                string deviceName = deviceList[i].Substring(begin + 12, end - begin - 12);
                comBox_CamSelect1.Items.Add(deviceName);
                comBox_CamSelect2.Items.Add(deviceName);
                m_CameraList[i] = deviceName;
            }
        }

        private void Form2_Load(object sender, EventArgs e)
        {
            tBoxTimeSpace.Text = "1000";  //计时器2的默认时间间隔显示
            Btn_FastSave.Enabled = false;
            timer1.Interval = 100;
            timer1.Enabled = true;
            timer1.Start();
            // 两台相机分别用两个线程采图，使其相互独立，防止低帧率的相机拖慢高帧率的相机
            Thread run1 = new Thread(new ParameterizedThreadStart(CameraRun));  //创建主线程
            Thread run2 = new Thread(new ParameterizedThreadStart(CameraRun));  
            run1.IsBackground = true;   //判断run是否为后台线程
            run2.IsBackground = true;   
            run1.Start(0);  //开启线程
            run2.Start(1);  

            string Date = DateTime.Now.ToShortDateString().ToString();  //获取当前时间
            Date = Date.Replace('/', '_');
            if (!Directory.Exists(Application.StartupPath + "\\快速保存的图片\\" + Date))
            {
                // 新建一个以当前日期为名字的文件夹，用于保存图片
                Directory.CreateDirectory(Application.StartupPath + "\\快速保存的图片\\" + Date);
            }
            baseImagePath = Application.StartupPath + "\\快速保存的图片\\" + Date + "\\";
        }//保存在bin>Dubug文件夹下面
        //每次一运行成功就会创建一个文件夹


        public void CameraRun(object index)  // 相机采图线程
        {
            int i = (int)index;
            float fps = 0f;
            dateTimes[i] = DateTime.Now;
            while (true)
            {
                if (!isOpened[i])
                {
                    lab_LED[i].ForeColor = Color.Black;
                    // Btn_OpenCam1.Image = Resources.保存;
                    // Btn_OpenCam1.Text = "打开相机";
                    Thread.Sleep(5);
                    continue;
                }
                if (isGrabing[i]) //按相机帧率显示图像实时刷新
                {
                    fps = 1000 / ((float)(DateTime.Now - dateTimes[i]).TotalMilliseconds);

                    Invoke(new Action(() =>
                    {
                        try
                        {
                            lab_FPS[i].Text = "相机帧率:" + fps.ToString("0.00");
                        }
                        catch
                        {

                        }
                    }));//该方法为了实时更新帧率
                    dateTimes[i] = DateTime.Now;

                    lab_LED[i].ForeColor = Color.Green;
                    m_Image[i] = m_MyCamera[i].GrabImage();
                    m_MyCamera[i].DisplayImage(m_Image[i], ref hWindowControl[i], ref hv_WindowHandle[i]);
                }
                else
                {
                    lab_LED[i].ForeColor = Color.Orange;
                    Thread.Sleep(5);
                }
            }
        }

        private void Btn_OpenCam1_Click(object sender, EventArgs e)
        {
            if (comBox_CamSelect1.SelectedItem == null)
            {
                MessageBox.Show("请先选择相机");
                return;
            }

            int camNum;
            Button button = (Button)sender;
            //判断一下计时器timer是否打开
            timer1.Start();//保证不会因为先打开了未连接相机的那个窗口后再打开连接了的那个导致曝光和增益不显示
            
            if (button.Name.Contains("1"))
                camNum = 0;
            else
                camNum = 1;
            if (button.Text == "打开相机")
            {
                if (isOpened[camNum])  //判断初始状态是否为已经打开了
                    return;

                /*else   //如果没打开，重置一下按钮   这段代码会有问题
                    Btn_OpenCam1.Image = Resources.相机;
                    Btn_OpenCam1.Text = "打开相机";*/


                deviceOpen[camNum] = m_MyCamera[camNum].OpenCamera1();   
                if (deviceOpen[camNum])   //加一个相机打开成功的标志，判断便于判断相机未连接时出现的情况
                {
                    isOpened[camNum] = true;
                    button.Image = Resources.相机蓝;
                    button.Text = "关闭相机";
                }
            }
            else
            {
                if (!isOpened[camNum])
                    return;

                isGrabing[camNum] = false;     // 先停止采图    
                isOpened[camNum] = false;
                button.Image = Resources.相机;
                button.Text = "打开相机";           
                switch (camNum)
                {
                    case 0:
                        Btn_StartGrab1.Image = Resources.采集;
                        Btn_StartGrab1.Text = "开始采集";
                        break;
                    case 1:
                        Btn_StartGrab2.Image = Resources.采集;
                        Btn_StartGrab2.Text = "开始采集";
                        break;
                }
                // 最后再关闭相机，防止最后一次采图和关闭相机冲突
                m_MyCamera[camNum].CloseCamera();
            }
            // 打开相机后，就无法选择相机了
            if (isOpened[0] || isOpened[1])
            {
                comBox_CamSelect1.Enabled = false;
                comBox_CamSelect2.Enabled = false;
            }
            else
            {
                comBox_CamSelect1.Enabled = true;
                comBox_CamSelect2.Enabled = true;
            }
        }

        private void Btn_StartGrab1_Click(object sender, EventArgs e)
        {
            int camNum;
            Button button = (Button)sender;
            if (button.Name.Contains("1"))
                camNum = 0;
            else
                camNum = 1;

            if (!isOpened[camNum])
                return;
            if (button.Text == "开始采集" )
            {
                isGrabing[camNum] = true;
                button.Image = Resources.采集蓝;
                button.Text = "停止采集";
            }
            else
            {
                isGrabing[camNum] = false;
                button.Image = Resources.采集;
                button.Text = "开始采集";
            }
        }

        private void Btn_SaveImg1_Click(object sender, EventArgs e)        //增加一个按帧率
        {
            int camNum;
            Button button = (Button)sender;
            if (button.Name.Contains("1"))
                camNum = 0;
            else
                camNum = 1;

            if (isGrabing[camNum])
            {
                MessageBox.Show("保存图片之前需停止采集");
                return;
            }
            m_MyCamera[camNum].SaveImage(m_Image[camNum]);
        }

        private void timer1_Tick(object sender, EventArgs e)      //参考
        {
            for (int i = 0; i < 2; i++)
            {
                if (isOpened[i])
                {
                    //lab_Expo[i].Text = "曝光时间:" + myCamera[i].GetParam("ExposureTime").ToString("0.0");
                    //lab_Gain[i].Text = "增益:" + myCamera[i].GetParam("Gain").ToString("0.0");

                    //修改的代码
                    if (m_MyCamera[i].GetParam("ExposureTime") == -1 || m_MyCamera[i].GetParam("Gain") == -1)
                    {
                        //打开失败的话让其恢复原始状态
                        //lab_LED[i].ForeColor = Color.Orange;
                        
                        timer1.Stop();
                        isOpened[i] = false;
                    }
                    lab_Expo[i].Text = "曝光时间:" + m_MyCamera[i].GetParam("ExposureTime").ToString("0.0");
                    lab_Gain[i].Text = "增益:" + m_MyCamera[i].GetParam("Gain").ToString("0.0");
                }
            }
            if (!isOpened[0] && !isOpened[1])
                Btn_FastSave.Enabled = false;
            else
                Btn_FastSave.Enabled = true;
        }

        private void textBox_Expo1_KeyPress(object sender, KeyPressEventArgs e)
        {
            TextBox textBox = (TextBox)sender;
            // 8 删除键 13回车 46 小数点，除此以外的按键都拒绝输入
            if (e.KeyChar != 8 && e.KeyChar != 13 && !char.IsDigit(e.KeyChar) && e.KeyChar != 46)
                e.Handled = true;

            if (e.KeyChar == 46)
            {
                // 小数点不能为第一位
                if (textBox.SelectionStart == 0)
                    e.Handled = true;
                // 小数点不能超过一个
                if (textBox.Text.Contains("."))
                    e.Handled = true;
            }
            // 按下回车键则执行SetParam_Click
            if (e.KeyChar == 13)
            {
                switch (textBox.Name)
                {
                    case "textBox_Expo1":
                        Btn_SetExpo1.PerformClick();
                        break;
                    case "textBox_Expo2":
                        Btn_SetExpo2.PerformClick();
                        break;
                    case "textBox_Gain1":
                        Btn_SetGain1.PerformClick();
                        break;
                    case "textBox_Gain2":
                        Btn_SetGain2.PerformClick();
                        break;
                }
            }
                
        }

        private void Btn_SetExpo1_Click(object sender, EventArgs e)
        {
            int camNum;
            Button button = (Button)sender;
            if (button.Name.Contains("1"))
                camNum = 0;
            else
                camNum = 1;

            if (isOpened[camNum] && textBoxes_Expo[camNum].Text != "")
            {
                try
                {
                    m_MyCamera[camNum].SetParam("ExposureTime", double.Parse(textBoxes_Expo[camNum].Text));
                }
                catch(Exception ex)
                {
                    MessageBox.Show(ex.Message);
                }
            }
        }

        private void Btn_SetGain1_Click(object sender, EventArgs e)
        {
            int camNum;
            Button button = (Button)sender;
            if (button.Name.Contains("1"))
                camNum = 0;
            else
                camNum = 1;

            if (isOpened[camNum] && textBoxes_Gain[camNum].Text != "")
            {
                try
                {
                    m_MyCamera[camNum].SetParam("Gain", double.Parse(textBoxes_Gain[camNum].Text));
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);
                }
            }
        }

        private void Btn_FastSave_Click(object sender, EventArgs e)
        {
            if(rBtnks.Checked)  //判断是不是选择到了快速保存还是按时间间隔保存
            {
                /* if (isGrabing[0] || isGrabing[1])
                 {
                     bool firstC = isGrabing[0];
                     bool secondC = isGrabing[1];
                     isGrabing[0] = false;
                     isGrabing[1] = false;
                     for (int i = 0; i < 1000; i++)
                     {
                         // 延时  保证在采集图像的线程中图像已经不再更新
                     }
                     string time = DateTime.Now.ToLongTimeString().ToString();
                     time = time.Replace(':', '_');
                     try
                     {
                         if (firstC)
                             HOperatorSet.WriteImage(m_Image[0], "bmp", 0, baseImagePath + time + " 1号" + ".bmp");
                         if (secondC)
                             HOperatorSet.WriteImage(m_Image[1], "bmp", 0, baseImagePath + time + " 2号" + ".bmp");
                     }
                     catch
                     {
                         MessageBox.Show("保存图像失败");
                     }

                     isGrabing[0] = firstC;
                     isGrabing[1] = secondC;
                 }*/

                FastSave();
            }
            else if(rBtnzl.Checked)
            {
                MessageBox.Show("请选择保存方式为按时间间隔保存！");
            }

        }

        private void btn_Time_jiange_Click(object sender, EventArgs e)     //按指定时间间隔保存
        {
            if (rBtnzl.Checked)  //判断是不是选择到了快速保存还是按时间间隔保存，要写一个自动循环保存的方法
            {
                flag = true;
                if(btn_Time_jiange.Text == "按时间间隔保存")
                {
                    if (Convert.ToInt32(tBoxTimeSpace.Text) != 0)  
                    {
                        timerfps.Interval = Convert.ToInt32(tBoxTimeSpace.Text);//读入时间间隔到定时器
                    }
                    timerfps.Start();    //开始定时器
                    btn_Time_jiange.Text = "停止保存";   //按钮变成停止保存
                }
                else if(btn_Time_jiange.Text == "停止保存")  //如果已经是“停止保存”，则恢复原来的按钮
                {
                    flag = false;
                    timerfps.Stop();
                    btn_Time_jiange.Text = "按时间间隔保存";
                }   
            }
            else if (rBtnks.Checked) 
            {
                MessageBox.Show("请选择保存方式为快速保存");
            }
            /*flag = true;
                if(Convert.ToInt32(tBoxTimeSpace.Text) != 0)
                {
                    timerfps.Interval = Convert.ToInt32(tBoxTimeSpace.Text);
                }
                timerfps.Start();*/
        }
        //flag = false;timerfps.Stop();

       /* if (button.Text == "开始采集" )
            {
                isGrabing[camNum] = true;
                button.Image = Resources.采集蓝;
                button.Text = "停止采集";
            }
            else
            {
                isGrabing[camNum] = false;
                button.Image = Resources.采集;
                button.Text = "开始采集";
            }*/


private void Form2_FormClosed(object sender, FormClosedEventArgs e)
        {
            timer1.Enabled = false;
            timer1.Stop();
            for (int i = 0; i < 2; i++)
            {
                if (!isOpened[i])
                    return;
                m_MyCamera[i].CloseCamera();
                isOpened[i] = false;
            }
            Thread.Sleep(100);
        }

        private void timerfps_Tick(object sender, EventArgs e)
        {
            if(flag)
            {
                FastSave();
            }
            else
            {
                MessageBox.Show("未触发定时保存图片");
            }
        }

        /*private void btnStop_Click(object sender, EventArgs e)     btnStop按钮已经删除
        {
            flag = false;
            timerfps.Stop();
        }*/

        /*private void btnSetTimeSpace_Click(object sender, EventArgs e)
        {
            timerfps.Interval = Convert.ToInt32(tBoxTimeSpace.Text);
        }*/

        private void rBtnks_CheckedChanged(object sender, EventArgs e)
        {
            if (rBtnks.Checked)
            {
                
                tBoxTimeSpace.Enabled = false;
                //btnSetTimeSpace.Enabled = false;
                btn_Time_jiange.Enabled = false;
                //btnStop.Enabled = false;
            }
            else if(rBtnzl.Checked)
            {
                
                tBoxTimeSpace.Enabled = true;
                //btnSetTimeSpace.Enabled = true;
                btn_Time_jiange.Enabled = true;
                //btnStop.Enabled = true;
            }
        }

        private void tBoxTimeSpace_TextChanged(object sender, EventArgs e)
        {
            timerfps.Interval = Convert.ToInt32(tBoxTimeSpace.Text);//读入时间间隔到定时器
        }

        private void textBox_Gain2_TextChanged(object sender, EventArgs e)
        {

        }

        private void tBoxTimeSpace_KeyPress(object sender, KeyPressEventArgs e)
        {
            TextBox textBox = (TextBox)sender;
            // 8 删除键 13回车 46 小数点，除此以外的按键都拒绝输入
            if (e.KeyChar != 8 && e.KeyChar != 13 && !char.IsDigit(e.KeyChar) )
                e.Handled = true;
            // 按下回车键则执行SetParam_Click
            if (e.KeyChar == 13)
            {
                btn_Time_jiange.PerformClick();
            }
    
        
        }

        private void tBoxTimeSpace_TextChanged_1(object sender, EventArgs e)
        {

        }

        private void comBox_CamSelect1_SelectedIndexChanged(object sender, EventArgs e)
        {
            // 任意一个comboBox选择了一个相机时，另一个comboBox自动选择另一个相机
            ComboBox curComboBox = (ComboBox)sender;
            string name = curComboBox.Name;
            int cur = name == "comBox_CamSelect1" ? 0 : 1;
            int another = cur == 0 ? 1 : 0;
            ComboBox anotherComboBox = another == 0 ? comBox_CamSelect1 : comBox_CamSelect2;
            anotherComboBox.SelectedIndex = curComboBox.SelectedIndex == 0 ? 1 : 0;
            // 只有第一次选择时才重新构造对象，否则只是修改下相机名称
            if (m_MyCamera[cur] == null)
            {
                m_MyCamera[cur] = new Camera(curComboBox.Text);
            } 
            else
            {
                m_MyCamera[cur].SetDeviceName(curComboBox.Text);
            }

            if (m_MyCamera[another] == null)
            {
                m_MyCamera[another] = new Camera(anotherComboBox.Text);
            } 
            else
            {
                m_MyCamera[another].SetDeviceName(anotherComboBox.Text);
            }
        }

        private void rB_CalAll_CheckedChanged(object sender, EventArgs e)
        {
            hWindowControl1.Focus();
            if (rB_CalROI.Checked)
            {
                Btn_DrawROI.Enabled = true;
                Btn_Calculate.Enabled = false;
            }
            else
            {
                Btn_DrawROI.Enabled = false;
                Btn_Calculate.Enabled = true;
            }
        }

        private void Btn_DrawROI_Click(object sender, EventArgs e)
        {
            int i = Rbtn_Cam1.Checked ? 0 : 1;
            // 先把对应相机暂停采集
            if (isGrabing[i])
            {
                isGrabing[i] = false;
                Button button = i == 0 ? Btn_StartGrab1 : Btn_StartGrab2;
                button.Image = Resources.采集;
                button.Text = "开始采集";
            }
            // 在对应窗口上绘制ROI
            if (m_Image[i] == null)
            {
                MessageBox.Show("请先采集图像！");
                return;
            }
            hWindowControl[i].Focus();
            camName1.Enabled = false;
            camName2.Enabled = false;
            skinGroupBox2.Enabled = false;
            skinGroupBox3.Enabled = false;
            skinGroupBox4.Enabled = false;
            m_MyHalcon.DrawROI(m_Image[i], hWindowControl[i], hv_WindowHandle[i], out m_TestImage);
            camName1.Enabled = true;
            camName2.Enabled = true;
            skinGroupBox2.Enabled = true;
            skinGroupBox3.Enabled = true;
            skinGroupBox4.Enabled = true;
            Btn_Calculate.Enabled = true;
        }

        private void Btn_Calculate_Click(object sender, EventArgs e)
        {
            int i = Rbtn_Cam1.Checked ? 0 : 1;
            if (m_Image[i] == null)
            {
                MessageBox.Show("请先采集图像！");
                return;
            }

            // 判断是否计算全图
            if (rB_CalAll.Checked)
            {
                if (isGrabing[i])
                {
                    isGrabing[i] = false;
                    Button button = i == 0 ? Btn_StartGrab1 : Btn_StartGrab2;
                    button.Image = Resources.采集;
                    button.Text = "开始采集";
                }
                m_TestImage = m_Image[i];
                m_MyCamera[i].DisplayImage(m_TestImage, ref hWindowControl[i], ref hv_WindowHandle[i]);
            }

            // 计算评价系数
            int nRet = m_MyHalcon.CalMeanIntensityGradient(m_TestImage, out string mig, out string misd, out double[] histo);
            Lab_MeanIntensityGradient.Text = mig;
            Lab_MeanIntensityGradient2.Text = misd;
        }

        private void FastSave()
        {
            if (isGrabing[0] || isGrabing[1])
            {
                bool firstC = isGrabing[0];
                bool secondC = isGrabing[1];
                isGrabing[0] = false;
                isGrabing[1] = false;
                for (int i = 0; i < 1000; i++)
                {
                    // 延时  保证在采集图像的线程中图像已经不再更新
                }
                string time = DateTime.Now.ToLongTimeString().ToString();
                time = time.Replace(':', '_');
                try
                {
                    if (firstC)
                        HOperatorSet.WriteImage(m_Image[0], "bmp", 0, baseImagePath + time + " 1号" + ".bmp");
                    if (secondC)
                        HOperatorSet.WriteImage(m_Image[1], "bmp", 0, baseImagePath + time + " 2号" + ".bmp");
                }
                catch
                {
                    MessageBox.Show("保存图像失败");
                }
                isGrabing[0] = firstC;
                isGrabing[1] = secondC;
            }
        }
    }
}
